

section my_code align=16 vstart=0

						
						mov eax, [cs:pgdt + 2 + 0x7c00] ;操作数的长度是4，不是2
						mov edx, 0
						mov ebx, 16
						div ebx
						mov ds, eax ;商, 0x7e0
						mov ebx, edx ;余数, 0

						;设置gdt
						;设置0号描述符
						mov dword [ebx], 0
						mov dword [ebx + 4], 0

						;设置1号描述符,基址是0，段界限是fffff,粒度是4kb,做es用的，用于输出内容到屏幕
						mov dword [ebx + 8], 0x0000ffff
						mov dword [ebx + 12], 0x00cf9200

						;设置2号描述符,基址是00007c00,段界限是001ff，粒度是1字节,代码段,不可读
						mov dword [ebx + 16], 0x7c0001ff
						mov dword [ebx + 20], 0x00409800

						;设置3号描述符，基址是00007c00,段界限是001ff，粒度是1字节,数据段，可读可写
						mov dword [ebx + 24], 0x7c0001ff
						mov dword [ebx + 28], 0x00409200

						;设置4号描述符，基址是00007c00，段界限是ffffe,粒度是4kb，栈段，可读可写
						mov dword [ebx + 32], 0x7c00fffe
						mov dword [ebx + 36], 0x00cf9600

						mov word [cs:pgdt + 0x7c00], 39 ;总字节数是40，40 - 1 = 39
						lgdt [cs:pgdt + 0x7c00]


						;打开A20地址线
						in al, 0x92
						or al, 0000_0010b
						out 0x92, al

						;关闭中断
						cli

						;打开保护模式
						mov eax, cr0
						or eax, 0x01
						mov cr0, eax

						;清流水线, gdt中的索引是0， 0x0010的二进制为 0000_0000_00010_000
						jmp 0x0010:flush



						;-----------------------------下面是32位的代码------------------------------
						bits 32
flush:					mov eax, 0000_0000_00011_000b ;gdt中的索引是3
						mov ds, eax
						mov eax, 0000_0000_00001_000b ;gdt中的索引是1
						mov es, eax
						mov eax, 0000_0000_00100_000b ;gdt中的索引是4
						mov ss, eax
						mov esp, 0 ;一定要设置，否则容易越界


						;对字符串进行冒泡排序
						mov ecx, sort_str_end - sort_str - 1 ;循环次数等于长度减一
outer:					mov ebx, 0
						push ecx ;保存外部的ecx

;内部循环,直接使用了外部的ecx，因为比较次数正好等于循环次数
inner:					mov ax, [sort_str + ebx]
						cmp ah, al
						jge i_1
						xchg ah, al ;交换
						mov [sort_str + ebx], ax ;交换之后的值回写
i_1:					inc ebx
						loop inner

						pop ecx ;恢复外部的ecx
						loop outer


						;将字符串输出到屏幕
						mov ecx, sort_str_end - sort_str
						mov ebx, 0
to_screen:				mov al, [sort_str + ebx]
						mov [es:0xb8000 + ebx * 2 + 160 * 12 + 30 * 2], al
						mov byte [es:0xb8000 + ebx * 2 + 1 + 160 * 12 + 30 * 2], 0x42
						inc ebx
						loop to_screen

						hlt ;停止cpu,这里一定要停止，不然的话，会把后面的数据当作指令来执行而报错


pgdt					dw 0		  ;gdt的界限,gdt的总字节数减1
						dd 0x00007e00 ;gdt的基地址

sort_str				db 'bxvaefcnmguv' ;需要排序的字符串,长度是12,相当于是db 'b', 'x', 'v', 'e'....
sort_str_end			nop

						
						times 510-($-$$) db 0
						db 0x55
						db 0xaa